﻿using System;
using System.Globalization;

namespace Microsoft.International.Formatters
{

    /// <summary>
    /// French France (fr-FR) and French Canadian (fr-CA) formatter
    /// </summary>
    [FormatCultureInfoAttribute("fr-FR")]
    [FormatCultureInfoAttribute("fr-CA")]
    internal sealed class FRStdFormatter : EuropeFormatter
    {

        /// <summary>
        /// Returns the Decimal value to String.
        /// </summary>
        /// <param name="num">Value to translate.</param>
        /// <returns>Returns the specified Decimal value to String.</returns>
        /// <remarks>Abstract method, must be implemented.</remarks>
        internal override String ConvertToLocalizedText(Decimal num)
        {
            String strMoins = String.Empty;
            Int32 value = (Int32)num;
            if (value < 0)
            {
                strMoins = "moins ";
                if (value == -2147483648)
                {
                    strMoins = strMoins + "deux milliards ";
                    value += 2000000000;
                }
                value = Math.Abs(value);
            }
            return (strMoins + this.BillionToString(value));
        }

        /// <summary>
        /// Convert billions (Int32 format) to String format.
        /// </summary>
        /// <param name="value">Value to convert</param>
        /// <returns>Returns a text which represents the specified value</returns>
        private String BillionToString(Int32 value)
        {
            if (value < 1000000000)
                return this.MillionToString(value);

            if (value == 1000000000)
                return "un milliard";

            Int32 reste = 0;
            Int32 milliard = Math.DivRem(value, 1000000000, out reste);
            String s = (milliard > 1) ? "s" : "";
            String strMilliard = String.Format(new CultureInfo("fr-FR"), "{0} milliard{1}", this.HundredToString(milliard), s);
            return String.Format(new CultureInfo("fr-FR"), "{0} {1}", strMilliard, this.ThousandToString(reste));
        }

        /// <summary>
        /// Convert millions (Int32 format) to String format.
        /// </summary>
        /// <param name="value">Value to convert</param>
        /// <returns>Returns a text which represents the specified value</returns>
        private String MillionToString(Int32 value)
        {
            if (value < 1000000)
                return this.HundredToString(value);

            if (value > 999999999)
                return this.BillionToString(value);

            if (value == 1000000)
                return "un million";

            Int32 reste = 0;
            Int32 millions = Math.DivRem(value, 1000000, out reste);
            String s = (millions > 1) ? "s" : "";
            String strMillions = String.Format(new CultureInfo("fr-FR"), "{0} million{1}", this.HundredToString(millions), s);
            return String.Format(new CultureInfo("fr-FR"), "{0} {1}", strMillions, this.ThousandToString(reste));
        }

        /// <summary>
        /// Convert thousands (Int32 format) to String format.
        /// </summary>
        /// <param name="value">Value to convert</param>
        /// <returns>Returns a text which represents the specified value</returns>
        private String ThousandToString(Int32 value)
        {
            if (value < 1000)
                return this.HundredToString(value);

            if (value > 999999)
                return this.MillionToString(value);

            if (value == 1000)
                return "mille";

            Int32 reste = 0;
            Int32 millier = Math.DivRem(value, 1000, out reste);
            String strMillier = "mille";
            if (millier != 1)
                strMillier = String.Format(new CultureInfo("fr-FR"), "{0} mille", this.HundredToString(millier).Replace("cents", "cent"));

            if (reste == 0)
                return strMillier;

            return String.Format(new CultureInfo("fr-FR"), "{0} {1}", strMillier, this.HundredToString(reste));
        }

        /// <summary>
        /// Convert hundreds (Int32 format) to String format.
        /// </summary>
        /// <param name="value">Value to convert</param>
        /// <returns>Returns a text which represents the specified value</returns>
        private String HundredToString(Int32 value)
        {
            if (value < 100)
                return this.TenToString(value);

            if (value > 999)
                return this.ThousandToString(value);

            if (value == 100)
                return "cent";

            Int32 reste = 0;
            Int32 centaine = Math.DivRem(value, 100, out reste);
            String strCentaine = "cent";
            if (centaine != 1)
                strCentaine = String.Format(new CultureInfo("fr-FR"), "{0} cent", this.TenToString(centaine));

            if (reste == 0)
                return String.Format(new CultureInfo("fr-FR"), "{0}s", strCentaine);

            return String.Format(new CultureInfo("fr-FR"), "{0} {1}", strCentaine, this.TenToString(reste));
        }

        /// <summary>
        /// Convert tens (Int32 format) to String format.
        /// </summary>
        /// <param name="value">Value to convert</param>
        /// <returns>Returns a text which represents the specified value</returns>
        private String TenToString(Int32 value)
        {
            if (value < 10)
                return this.UnitToString(value);

            if (value > 99)
                return this.HundredToString(value);

            switch (value)
            {
                case 10: return "dix";
                case 11: return "onze";
                case 12: return "douze";
                case 13: return "treize";
                case 14: return "quatorze";
                case 15: return "quinze";
                case 16: return "seize";
                case 20: return "vingt";
                case 21: return "vingt et un";
                case 30: return "trente";
                case 31: return "trente et un";
                case 40: return "quarante";
                case 41: return "quarante et un";
                case 70: return "soixante-dix";
                case 71: return "soixante et onze";
                case 80: return "quatre-vingts";
                case 50: return "cinquante";
                case 51: return "cinquante et un";
                case 60: return "soixante";
                case 61: return "soixante et un";
            }
            if (value.Between(72, 79))
                return String.Format(new CultureInfo("fr-FR"), "soixante-{0}", this.TenToString(value - 60));
            if (value.Between(90, 99))
                return String.Format(new CultureInfo("fr-FR"), "quatre-vingt-{0}", this.TenToString(value - 80));
            if (value.Between(81, 89))
                return String.Format(new CultureInfo("fr-FR"), "quatre-vingt-{0}", this.UnitToString(value.GetUnit()));

            return String.Format(new CultureInfo("fr-FR"), "{0}-{1}", this.TenToString(value.GetTen()), this.UnitToString(value.GetUnit()));
        }

        /// <summary>
        /// Convert units (Int32 format) to String format.
        /// </summary>
        /// <param name="value">Value to convert</param>
        /// <returns>Returns a text which represents the specified value</returns>
        private String UnitToString(Int32 value)
        {
            if (value > 9)
                return this.TenToString(value);

            String result = String.Empty;
            switch (value.ToString(new CultureInfo("fr-FR")))
            {
                case "0": return "zéro";
                case "1": return "un";
                case "2": return "deux";
                case "3": return "trois";
                case "4": return "quatre";
                case "5": return "cinq";
                case "6": return "six";
                case "7": return "sept";
                case "8": return "huit";
                case "9": return "neuf";
            }
            return result;
        }

    }

}